home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Marathon Map Viewer / @Source / levelView.cpp < prev    next >
Text File  |  1995-06-06  |  16KB  |  581 lines

  1. /*-----------------------------------------------------------------
  2.     Copyright ©1994 Steve Israelson
  3.     
  4.     This file contains the code for the "levelView" class.
  5.     This class handles the displaying of a level in a view.
  6. -----------------------------------------------------------------*/
  7.  
  8. #include "levelView.h"
  9. #include "commandNumbers.h"
  10. #include "myApplication.h"
  11. #include "levelUtils.h"
  12.  
  13.  
  14. /*-----------------------------------------------------------------
  15.     Make a new levelView.  Called from the URegistrar.
  16. -----------------------------------------------------------------*/
  17. levelView *levelView::CreateViewStream(LStream *inStream)
  18.     {
  19.     return (new levelView(inStream));
  20.     }
  21.  
  22. /*-----------------------------------------------------------------
  23.     Initialize the view to a known state.
  24. -----------------------------------------------------------------*/
  25. levelView::levelView(LStream *inStream) : LView(inStream)
  26.     {
  27.     theLevelData = nil;
  28.     scaleFactor = 63;
  29.     showGrid = false;
  30.     showPoints = true;
  31.     showLines = true;
  32.     showObjects = false;
  33.  
  34.     Point    where = {0x7fff, 0x7fff};
  35.     setScale(64, where);
  36.  
  37.     if (!IsTarget()) 
  38.         SwitchTarget(this);
  39.     }
  40.  
  41. /*-----------------------------------------------------------------
  42.     Initialize the view to a known state.
  43. -----------------------------------------------------------------*/
  44. levelView::levelView(const SPaneInfo &inPaneInfo, const SViewInfo &inViewInfo) : LView(inPaneInfo, inViewInfo)
  45.     {
  46.     theLevelData = nil;
  47.     scaleFactor = 63;
  48.     showGrid = false;
  49.     showPoints = true;
  50.     showLines = true;
  51.     showObjects = false;
  52.  
  53.     Point    where = {0x7fff, 0x7fff};
  54.     setScale(64, where);
  55.  
  56.     if (!IsTarget()) 
  57.         SwitchTarget(this);
  58.     }
  59.  
  60. /*-----------------------------------------------------------------
  61.     Clean up when we are disposed.
  62. -----------------------------------------------------------------*/
  63. levelView::~levelView()
  64.     {
  65.     }
  66.  
  67. /*-----------------------------------------------------------------
  68.     After the window is created, lets do some stuff.
  69. -----------------------------------------------------------------*/
  70. void levelView::FinishCreate()
  71.     {
  72.     fixImageSize();
  73.     LView::FinishCreate();
  74.     Refresh();
  75.     }
  76.  
  77. /*-----------------------------------------------------------------
  78.     This is so that the scroll bars will work properly.
  79.     They use the image size to decide if scrolling is possible.
  80.     The image is the area that our entire level will take up.
  81.     When this view is put into a ScrollView, the ScrollView will
  82.     set up the scroll bars so we can view all of the image, even
  83.     if it doesn't fit in the window all at once.
  84. -----------------------------------------------------------------*/
  85. void levelView::fixImageSize(void)
  86.     {
  87.     long    width = offset + 32768L / scaleFactor;
  88.     long    height = offset + 32768L / scaleFactor;
  89.     ResizeImageTo(width, height, false);
  90.     }
  91.  
  92. /*-----------------------------------------------------------------
  93.     Zoom centered on the point where, unless where = 0x7fff, 0x7fff
  94.     There has to be an easier way to do this!
  95. -----------------------------------------------------------------*/
  96. void levelView::setScale(long newScale, Point where)
  97.     {
  98.     Rect        frame;
  99.     long        centerX, centerY, newCenterX, newCenterY;
  100.     long        oldScale = scaleFactor;
  101.  
  102.     if (newScale < 4)
  103.         newScale = 4;
  104.     if (newScale > 1024)
  105.         newScale = 1024;
  106.         
  107.     offset = 0x8000L / scaleFactor;
  108.  
  109.     FocusDraw();
  110.     CalcLocalFrameRect(frame);
  111.     // calc center in mara coords
  112.     if (where.h == 0x7fff && where.v == 0x7fff)
  113.         {
  114.         centerX = (frame.left + frame.right) / 2 * scaleFactor;
  115.         centerY = (frame.top + frame.bottom) / 2 * scaleFactor;
  116.         }
  117.     else
  118.         {
  119.         centerX = where.h * scaleFactor;
  120.         centerY = where.v * scaleFactor;
  121.         }
  122.  
  123.     scaleFactor = newScale;
  124.     offset = 0x8000L / scaleFactor;
  125.  
  126.     fixImageSize();
  127.  
  128.     // fix up how big the window can be.
  129.     // if we zoom way out, we dont want the window to be bigger than us.
  130.     SDimension16    newSize = {65535L / scaleFactor, 65535L / scaleFactor};
  131.     LWindow *owner = LWindow::FetchWindowObject(GetMacPort());
  132.     if (owner && owner->IsVisible())
  133.         {
  134.         Rect    theRect = (*((WindowPeek)GetMacPort())->contRgn)->rgnBBox;
  135.  
  136.         owner->SetStandardSize(newSize);
  137.         
  138.         if (theRect.right - theRect.left > newSize.width + 15)
  139.             theRect.right = theRect.left + newSize.width + 15;
  140.         if (theRect.bottom - theRect.top > newSize.height + 15)
  141.             theRect.bottom = theRect.top + newSize.height + 15;
  142.         owner->DoSetBounds(theRect);
  143.  
  144.         owner->GetMinMaxSize(theRect);
  145.         theRect.right = newSize.width + 15;
  146.         theRect.bottom = newSize.height + 15;
  147.         owner->SetMinMaxSize(theRect);
  148.         }
  149.  
  150.     SDimension32    theImageSize;
  151.     GetImageSize(theImageSize);
  152.     
  153.     CalcLocalFrameRect(frame);
  154.     // calc width in marathon coords
  155.     newCenterX = (frame.right - frame.left) / 2 * scaleFactor;
  156.     newCenterY = (frame.bottom - frame.top) / 2 * scaleFactor;
  157.  
  158.     // scroll to the center point
  159.  
  160.     long    newXpos = (centerX - newCenterX) / scaleFactor;
  161.     long     newYpos = (centerY - newCenterY) / scaleFactor;
  162.     if (newXpos < 0)
  163.         newXpos = 0;
  164.     if (newYpos < 0)
  165.         newYpos = 0;
  166.     if (newXpos + (frame.right - frame.left) > theImageSize.width)
  167.         newXpos = theImageSize.width - (frame.right - frame.left);
  168.     if (newYpos + (frame.bottom - frame.top) > theImageSize.height)
  169.         newYpos = theImageSize.height - (frame.bottom - frame.top);
  170.     ScrollImageTo(newXpos, newYpos, false);
  171.     
  172.     Refresh();
  173.     }
  174.  
  175. /*-----------------------------------------------------------------
  176.     Some one will eventually give us a level to display.
  177.     There may be a better way to handle this, but this method
  178.     allows us to make one view that can display different
  179.     levels in it, just by calling this when a new level
  180.     needs to be displayed.
  181. -----------------------------------------------------------------*/
  182. void levelView::setLevelData(levelData *newLevelData)
  183.     {
  184.     theLevelData = newLevelData;
  185.  
  186.     Point    mapCenter;
  187.     long    centerX, centerY;
  188.     getMapCenter(theLevelData, ¢erX, ¢erY);
  189.     mapCenter.h = offset + centerX / scaleFactor;
  190.     mapCenter.v = offset + centerY / scaleFactor;
  191.     setScale(scaleFactor, mapCenter);
  192.     }
  193.  
  194. /*-----------------------------------------------------------------
  195.     Handle a mouse click.  This is where you can do different
  196.     things, depending on what tool the user has selected.
  197. -----------------------------------------------------------------*/
  198. void levelView::ClickSelf(const SMouseDownEvent &inMouseDown)
  199.     {
  200.     FocusDraw();
  201.     if (!IsTarget()) 
  202.         {
  203.         SwitchTarget(this);
  204.         }
  205. //    short        tool = theApp->theToolPalette->curTool;
  206.     Boolean        shiftState = (inMouseDown.macEvent.modifiers & shiftKey) ? true: false;
  207.     
  208. //    switch (tool)
  209. //        {
  210. //        case tool_arrow:
  211. //    write code for handling clicks with the arrow tool...
  212.  
  213.     }
  214.  
  215. /*-----------------------------------------------------------------
  216.     Find out if menu commands are allowed.  This is called when
  217.     the user clicks in the menu bar.
  218. -----------------------------------------------------------------*/
  219. void levelView::FindCommandStatus(
  220.     CommandT    inCommand,
  221.     Boolean        &outEnabled,
  222.     Boolean        &outUsesMark,
  223.     Char16        &outMark,
  224.     Str255        outName)
  225.     {
  226.     outUsesMark = false;
  227.     
  228.     switch (inCommand) 
  229.         {
  230.         case cmd_toggleGrid:
  231.             outUsesMark = true;
  232.             if (showGrid)
  233.                 outMark = '';    /* check mark */
  234.             else
  235.                 outMark = ' ';
  236.             outEnabled = true;
  237.             break;
  238.         case cmd_togglePoints:
  239.             outUsesMark = true;
  240.             if (showPoints)
  241.                 outMark = '';    /* check mark */
  242.             else
  243.                 outMark = ' ';
  244.             outEnabled = true;
  245.             break;
  246.         case cmd_toggleLines:
  247.             outUsesMark = true;
  248.             if (showLines)
  249.                 outMark = '';    /* check mark */
  250.             else
  251.                 outMark = ' ';
  252.             outEnabled = true;
  253.             break;
  254.         case cmd_toggleObjects:
  255.             outUsesMark = true;
  256.             if (showObjects)
  257.                 outMark = '';    /* check mark */
  258.             else
  259.                 outMark = ' ';
  260.             outEnabled = true;
  261.             break;
  262.         case cmd_zoomIn:
  263.         case cmd_zoomOut:
  264.             outEnabled = true;
  265.             break;
  266.         case cmd_Nothing:
  267.         default:
  268.             LCommander::FindCommandStatus(inCommand, outEnabled, outUsesMark,
  269.                                 outMark, outName);
  270.             break;
  271.         }
  272.     }
  273.  
  274. /*-----------------------------------------------------------------
  275.     Do a menu command.  This is called after the user selects
  276.     a command from the menu.
  277. -----------------------------------------------------------------*/
  278. Boolean levelView::ObeyCommand(CommandT inCommand, void *ioParam)
  279.     {
  280.     Boolean            cmdHandled = true;
  281.     
  282.     switch (inCommand) 
  283.         {
  284.         case cmd_togglePoints:
  285.             showPoints = !showPoints;
  286.             Refresh();
  287.             break;
  288.         case cmd_toggleLines:
  289.             showLines = !showLines;
  290.             Refresh();
  291.             break;
  292.         case cmd_toggleObjects:
  293.             showObjects = !showObjects;
  294.             Refresh();
  295.             break;
  296.         case cmd_toggleGrid:
  297.             showGrid = !showGrid;
  298.             Refresh();
  299.             break;
  300.         case cmd_zoomIn:
  301.             Point    where1 = {0x7fff, 0x7fff};
  302.             setScale(scaleFactor - 8, where1);
  303.             break;
  304.         case cmd_zoomOut:
  305.             Point    where2 = {0x7fff, 0x7fff};
  306.             setScale(scaleFactor + 8, where2);
  307.             break;
  308.         case cmd_Nothing:
  309.         default:
  310.             return LCommander::ObeyCommand(inCommand, ioParam);
  311.             break;
  312.         }
  313.     return cmdHandled;
  314.     }
  315.  
  316. /*-----------------------------------------------------------------
  317.     Draw this view.  This gets called by PowerPlant when it needs
  318.     part or all of the view re-drawn.
  319. -----------------------------------------------------------------*/
  320. void levelView::DrawSelf()
  321.     {
  322.     Rect        frame;
  323.     RGBColor    greyColor = {10000, 10000, 10000};
  324.  
  325.     CalcLocalFrameRect(frame);
  326.     
  327.     RGBForeColor(&greyColor);
  328.     PaintRect(&frame);
  329.     ForeColor(blackColor);
  330.  
  331.     drawPolygons();
  332.     if (showGrid)
  333.         drawGrid();
  334.     if (showLines)
  335.         drawLines();
  336.     if (showPoints)
  337.         drawPoints();
  338.     if (showObjects)
  339.         drawObjects();
  340.     PenNormal();
  341.     }
  342.  
  343. /*-----------------------------------------------------------------
  344.     Draw a grid.  Nothing fancy.
  345. -----------------------------------------------------------------*/
  346. void levelView::drawGrid(void)
  347.     {
  348.     long        scaledX = 0, maxX, x;
  349.     Rect        frame;
  350.  
  351.     ForeColor(redColor);
  352.     PenPat(&qd.gray);
  353.     CalcLocalFrameRect(frame);
  354.     if (frame.right > frame.bottom)
  355.         maxX = frame.right;
  356.     else
  357.         maxX = frame.bottom;
  358.     for (x = 0; scaledX < maxX; x += 4096)
  359.         {
  360.         scaledX = x / scaleFactor;
  361.         MoveTo(scaledX, 0);
  362.         LineTo(scaledX, 32000);
  363.         }
  364.     for (x = 0, scaledX = 0; scaledX < maxX; x += 4096)
  365.         {
  366.         scaledX = x / scaleFactor;
  367.         MoveTo(0, scaledX);
  368.         LineTo(32000, scaledX);
  369.         }
  370.     PenNormal();
  371.     }
  372.  
  373. /*-----------------------------------------------------------------
  374.     Draw all the objects.
  375. -----------------------------------------------------------------*/
  376. void levelView::drawObjects(void)
  377.     {
  378.     for (int x = 0; x < theLevelData->numObjects; ++x)
  379.         drawObject(x);
  380.     }
  381.  
  382. /*-----------------------------------------------------------------
  383.     Draw one object.
  384. -----------------------------------------------------------------*/
  385. void levelView::drawObject(short x)
  386.     {
  387.     RGBColor    objectColor = {65535, 0, 0};
  388.     Rect        theRect;
  389.  
  390.     theRect.left = offset + theLevelData->theObjects[x].x / scaleFactor - 4;
  391.     theRect.top = offset + theLevelData->theObjects[x].y / scaleFactor - 4;
  392.     theRect.right = theRect.left + 4 * 2;
  393.     theRect.bottom = theRect.top + 4 * 2;
  394.  
  395.     short        angle = (theLevelData->theObjects[x].facing * 360L) / 512L + 20 + 90;
  396.  
  397.     InsetRect(&theRect, -1, -1);
  398.     ForeColor(blackColor);
  399.     PaintOval(&theRect);
  400.     InsetRect(&theRect, 1, 1);
  401.  
  402.     switch (theLevelData->theObjects[x].type)
  403.         {
  404.         case object_monster:
  405.             objectColor.red = 65535;
  406.             objectColor.green = 0;
  407.             objectColor.blue = 0;
  408.             RGBForeColor(&objectColor);
  409.             break;
  410.         case object_scenery:
  411.             objectColor.red = 65535;
  412.             objectColor.green = 65535;
  413.             objectColor.blue = 65535;
  414.             RGBForeColor(&objectColor);
  415.             break;
  416.         case object_weapon:
  417.             objectColor.red = 0;
  418.             objectColor.green = 65535;
  419.             objectColor.blue = 0;
  420.             RGBForeColor(&objectColor);
  421.             break;
  422.         case object_player:
  423.             objectColor.red = 0;
  424.             objectColor.green = 0;
  425.             objectColor.blue = 65535;
  426.             RGBForeColor(&objectColor);
  427.             break;
  428.         case object_goal:
  429.             objectColor.red = 65535;
  430.             objectColor.green = 65535;
  431.             objectColor.blue = 0;
  432.             RGBForeColor(&objectColor);
  433.             break;
  434.         }
  435.     PaintArc(&theRect, angle, 320);
  436.     }
  437.  
  438. /*-----------------------------------------------------------------
  439.     Draw the lines.  Draws light lines when there is no wall.
  440. -----------------------------------------------------------------*/
  441. void levelView::drawLines(void)
  442.     {
  443.     RGBColor    greenColor = {0, 65535, 0};
  444.     RGBColor    greyColor = {40000, 40000, 40000};
  445.     short        lineSize = 1;
  446.  
  447.     for (int x = 0; x < theLevelData->numLines; ++x)
  448.         {
  449.         LINSdata    *theLine = &theLevelData->theLines[x];
  450.         if (theLine->leftPoly != -1 && theLine->rightPoly != -1)
  451.             {
  452.             // if the floors are the same height, then there is no wall
  453.             if (theLevelData->thePolys[theLine->leftPoly].floorHeight ==
  454.                         theLevelData->thePolys[theLine->rightPoly].floorHeight)
  455.                 {
  456.                 PenSize(lineSize, lineSize);
  457.                 RGBForeColor(&greyColor);
  458.                 }
  459.             else
  460.                 {
  461.                 PenNormal();
  462.                 PenSize(lineSize, lineSize);
  463.                 RGBForeColor(&greenColor);
  464.                 }
  465.             }
  466.         else
  467.             {    // if there is no polygon on one side, the there must be a wall
  468.             PenNormal();
  469.             PenSize(lineSize ,lineSize);
  470.             RGBForeColor(&greenColor);
  471.             }
  472.         // actually draw the line now that its color has been determined
  473.         PNTSdata    *pointA, *pointB;
  474.         pointA = &theLevelData->thePoints[theLine->pointA];
  475.         pointB = &theLevelData->thePoints[theLine->pointB];
  476.         MoveTo(offset + pointA->x / scaleFactor, offset + pointA->y / scaleFactor);
  477.         LineTo(offset + pointB->x / scaleFactor, offset + pointB->y / scaleFactor);
  478.         }
  479.     ForeColor(blackColor);
  480.     PenNormal();
  481.     }
  482.  
  483. /*-----------------------------------------------------------------
  484.     Draw some cool points.  Make a circle with a thin black line
  485.     around it.
  486. -----------------------------------------------------------------*/
  487. void levelView::drawPoints(void)
  488.     {
  489.     short        x;
  490.     Rect        theRect;
  491.     RGBColor    greenColor = {0, 65535, 0};
  492.     short        pointSize = 2;
  493.     
  494.     PenNormal();
  495.  
  496.     for (x = 0; x < theLevelData->numPoints; ++x)
  497.         {
  498.         PNTSdata    *thePoint;
  499.     
  500.         thePoint = &theLevelData->thePoints[x];
  501.  
  502.         theRect.left = offset + thePoint->x / scaleFactor - pointSize;
  503.         theRect.top = offset + thePoint->y / scaleFactor - pointSize;
  504.         theRect.right = theRect.left + (pointSize << 1);
  505.         theRect.bottom = theRect.top + (pointSize << 1);
  506.  
  507.         ForeColor(blackColor);
  508.         InsetRect(&theRect, -1, -1);
  509.         PaintOval(&theRect);
  510.         RGBForeColor(&greenColor);
  511.         InsetRect(&theRect, 1, 1);
  512.         PaintOval(&theRect);
  513.         }
  514.     }
  515.  
  516. /*-----------------------------------------------------------------
  517.     Make and draw a polygon.
  518. -----------------------------------------------------------------*/
  519. void levelView::drawPolygons(void)
  520.     {
  521.     RGBColor    liteColor = {0, 0, 65535};
  522.     PolyHandle    thePolyHandle;
  523.  
  524.     RGBForeColor(&liteColor);        // default color
  525.     for (int x = 0; x < theLevelData->numPolys; ++x)
  526.         {
  527.         thePolyHandle = makePolyPolygon(x);
  528.         if (thePolyHandle)
  529.             {
  530.             // paint poly
  531.             PaintPoly(thePolyHandle);
  532.             // dispose poly
  533.             KillPoly(thePolyHandle);
  534.             }
  535.         PenNormal();
  536.         }
  537.     ForeColor(blackColor);
  538.     }
  539.  
  540. /*-----------------------------------------------------------------
  541.     Make a quickdraw polygon for a poly.
  542. -----------------------------------------------------------------*/
  543. PolyHandle levelView::makePolyPolygon(long thePoly)
  544.     {
  545.     if (thePoly == -1 || thePoly >= theLevelData->numPolys)
  546.         return nil;
  547.  
  548.     // open poly here
  549.     PolyHandle    thePolyHandle = OpenPoly();
  550.     Boolean     first = true;
  551.     short        firstX, firstY;
  552.     short        *vertexIndex;
  553.     short        vertexCount;
  554.  
  555.     vertexIndex = theLevelData->thePolys[thePoly].vertexIndex;
  556.     vertexCount = theLevelData->thePolys[thePoly].vertexCount;
  557.     for (int y = 0; y < vertexCount; ++y)
  558.         {
  559.         PNTSdata    *pointA;
  560.     
  561.         pointA = &theLevelData->thePoints[vertexIndex[y]];
  562.         if (first)
  563.             {
  564.             first = false;
  565.             firstX = offset + pointA->x / scaleFactor;
  566.             firstY = offset + pointA->y / scaleFactor;
  567.             MoveTo(firstX, firstY);
  568.             }
  569.         else
  570.             LineTo(offset + pointA->x / scaleFactor, offset + pointA->y / scaleFactor);
  571.         }
  572.     // close poly here
  573.     LineTo(firstX, firstY);
  574.     ClosePoly();        // closes the fisrt and last line as well
  575.     return thePolyHandle;
  576.     }
  577.  
  578.  
  579.  
  580.  
  581.